#ifndef _WX_XML_H_
#define _WX_XML_H_

#include "wx/defs.h"
#include "wx/string.h"
#include "wx/object.h"
#include "wx/list.h"

#ifdef WXMAKINGDLL_XML
#define WXDLLIMPEXP_XML WXEXPORT
#elif defined(WXUSINGDLL)
#define WXDLLIMPEXP_XML WXIMPORT
#else // not making nor using DLL
#define WXDLLIMPEXP_XML
#endif

class wxXmlNode;
class wxXmlProperty;
class wxXmlDocument;
class wxXmlIOHandler;
class wxInputStream;
class wxOutputStream;

enum wxXmlNodeType {
  wxXML_ELEMENT_NODE =  1,
  wxXML_ATTRIBUTE_NODE =  2,
  wxXML_TEXT_NODE =  3,
  wxXML_CDATA_SECTION_NODE =  4,
  wxXML_ENTITY_REF_NODE =  5,
  wxXML_ENTITY_NODE =  6,
  wxXML_PI_NODE =  7,
  wxXML_COMMENT_NODE =  8,
  wxXML_DOCUMENT_NODE =  9,
  wxXML_DOCUMENT_TYPE_NODE = 10,
  wxXML_DOCUMENT_FRAG_NODE = 11,
  wxXML_NOTATION_NODE = 12,
  wxXML_HTML_DOCUMENT_NODE = 13
};

class wxXmlProperty {
  public:
    wxXmlProperty() : m_next( NULL ) {}
    wxXmlProperty( const wxString& name, const wxString& value, wxXmlProperty *next = NULL )
      : m_name( name ), m_value( value ), m_next( next ) {}
    virtual ~wxXmlProperty() {}
    wxString GetName() const { return m_name; }
    wxString GetValue() const { return m_value; }
    wxXmlProperty *GetNext() const { return m_next; }
    void SetName( const wxString& name ) { m_name = name; }
    void SetValue( const wxString& value ) { m_value = value; }
    void SetNext( wxXmlProperty *next ) { m_next = next; }
  private:
    wxString m_name;
    wxString m_value;
    wxXmlProperty *m_next;
};

class wxXmlNode {
  public:
    wxXmlNode() : m_properties( NULL ), m_parent( NULL ),
      m_children( NULL ), m_next( NULL ) {}
    wxXmlNode( wxXmlNode *parent, wxXmlNodeType type,
               const wxString& name, const wxString& content = wxEmptyString,
               wxXmlProperty *props = NULL, wxXmlNode *next = NULL );
    virtual ~wxXmlNode();
    wxXmlNode( const wxXmlNode& node );
    wxXmlNode& operator=( const wxXmlNode& node );
    wxXmlNode( wxXmlNodeType type, const wxString& name, const wxString& content = wxEmptyString );
    virtual void AddChild( wxXmlNode *child );
    virtual bool InsertChild( wxXmlNode *child, wxXmlNode *followingNode );
    bool InsertChildAfter( wxXmlNode *child, wxXmlNode *precedingNode );
    virtual bool RemoveChild( wxXmlNode *child );
    virtual void AddProperty( const wxString& name, const wxString& value );
    virtual bool DeleteProperty( const wxString& name );
    wxXmlNodeType GetType() const { return m_type; }
    wxString GetName() const { return m_name; }
    wxString GetContent() const { return m_content; }
    bool IsWhitespaceOnly() const;
    int GetDepth( wxXmlNode *grandparent = NULL ) const;
    wxString GetNodeContent() const;
    wxXmlNode *GetParent() const { return m_parent; }
    wxXmlNode *GetNext() const { return m_next; }
    wxXmlNode *GetChildren() const { return m_children; }
    wxXmlProperty *GetProperties() const { return m_properties; }
    bool GetPropVal( const wxString& propName, wxString *value ) const;
    wxString GetPropVal( const wxString& propName, const wxString& defaultVal ) const;
    bool HasProp( const wxString& propName ) const;
    void SetType( wxXmlNodeType type ) { m_type = type; }
    void SetName( const wxString& name ) { m_name = name; }
    void SetContent( const wxString& con ) { m_content = con; }
    void SetParent( wxXmlNode *parent ) { m_parent = parent; }
    void SetNext( wxXmlNode *next ) { m_next = next; }
    void SetChildren( wxXmlNode *child ) { m_children = child; }
    void SetProperties( wxXmlProperty *prop ) { m_properties = prop; }
    virtual void AddProperty( wxXmlProperty *prop );
    wxString GetAttribute( const wxString& attrName, const wxString& defaultVal ) const {
      return GetPropVal( attrName, defaultVal );
    }
    bool GetAttribute( const wxString& attrName, wxString *value ) const {
      return GetPropVal( attrName, value );
    }
    void AddAttribute( const wxString& attrName, const wxString& value ) {
      AddProperty( attrName, value );
    }
    wxXmlProperty* GetAttributes() const {
      return GetProperties();
    }
  private:
    wxXmlNodeType m_type;
    wxString m_name;
    wxString m_content;
    wxXmlProperty *m_properties;
    wxXmlNode *m_parent, *m_children, *m_next;

    void DoCopy( const wxXmlNode& node );
};

#define wxXML_NO_INDENTATION           (-1)

enum wxXmlDocumentLoadFlag {
  wxXMLDOC_NONE = 0,
  wxXMLDOC_KEEP_WHITESPACE_NODES = 1
};

class wxXmlDocument : public wxObject {
  public:
    wxXmlDocument();
    wxXmlDocument( const wxString& filename, const wxString& encoding = wxT( "UTF-8" ) );
    wxXmlDocument( wxInputStream& stream, const wxString& encoding = wxT( "UTF-8" ) );
    virtual ~wxXmlDocument() { wxDELETE( m_root ); }
    wxXmlDocument( const wxXmlDocument& doc );
    wxXmlDocument& operator=( const wxXmlDocument& doc );
    virtual bool Load( const wxString& filename, const wxString& encoding = wxT( "UTF-8" ), int flags = wxXMLDOC_NONE );
    virtual bool Load( wxInputStream& stream, const wxString& encoding = wxT( "UTF-8" ), int flags = wxXMLDOC_NONE );
    virtual bool Save( const wxString& filename, int indentstep = 1 ) const;
    virtual bool Save( wxOutputStream& stream, int indentstep = 1 ) const;
    bool IsOk() const { return m_root != NULL; }
    wxXmlNode *GetRoot() const { return m_root; }
    wxString GetFileEncoding() const { return m_fileEncoding; }
    wxXmlNode *DetachRoot() { wxXmlNode *old = m_root; m_root = NULL; return old; }
    void SetRoot( wxXmlNode *node ) { wxDELETE( m_root ); m_root = node; }
    void SetFileEncoding( const wxString& encoding ) { m_fileEncoding = encoding; }
  private:
    wxString m_filename;
    wxString m_fileEncoding;
    wxXmlNode *m_root;
    void DoCopy( const wxXmlDocument& doc );
    DECLARE_CLASS( wxXmlDocument )
};

#endif
